#!/usr/binary/env python3
# -*- encoding: utf-8 -*-
"""
@File    :   SSL.py
@Time    :   2024-07-23 09:56
@Author  :   坐公交也用券
@Version :   1.0
@Contact :   faith01238@hotmail.com
@Homepage : https://liumou.site
@Desc    :   当前文件作用
"""
import logging
import os
import subprocess
import sys
from argparse import ArgumentParser
from sys import exit

# 创建一个自定义的日志记录器
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# 创建一个自定义的日志处理器，设置其输出格式
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d | %(funcName)s | %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)


class UpgradeOpenSSL:
	def __init__(self, urls, dst, file):
		"""

		:param urls: 源码下载链接
		:param dst: 程序安装路径
		:param file: 压缩包文件名,如果不指定则默认使用url中的文件名
		"""
		self.file = file
		self.dst = dst
		file_name_dir_get = str(file).replace(".tar.gz", "")
		self.tmp_dir = os.path.join(os.getcwd(), file_name_dir_get)
		self.url = urls
		self.filename = str(self.url.split("/")[-1])
		self.openssl_path = os.path.join(self.dst, "binary/openssl")
		self.openssl_old_path = None
		self.lib = os.path.join(self.dst, "lib")

	def download(self):
		"""
		下载压缩包
		:return:
		"""
		if self.file is not None and len(self.file) >= 6:
			if os.path.isfile(self.file):
				print(f"使用自定义本地文件进行安装: [ {self.file} ]")
				self.filename = self.file
				self.tmp_dir = os.path.join(os.getcwd(), str(self.file).replace(".tar.gz", ""))
				return
		# 如果文件已经存在则先删除
		if os.path.exists(self.filename):
			os.remove(self.filename)
		print("正在下载压缩包")
		# 开始下载并判断下载结果，如果下载失败则退出
		if os.system(f"wget {self.url}") != 0:
			print("下载失败")
			exit(1)

	def untar(self):
		"""
		解压压缩包
		:return:
		"""
		print("正在解压压缩包")
		if os.system(f"tar -xvf {self.filename}") != 0:
			print("解压失败")
			exit(2)

	def compile(self):
		"""
		编译源码
		:return:
		"""
		if not os.path.isdir(self.tmp_dir):
			print(f"找不到解压目录: {self.tmp_dir}")
			exit(4)
		print("正在编译源码")
		os.chdir(self.tmp_dir)
		cmd = f"./Configure --prefix={self.dst}"
		if os.system(cmd) != 0:
			print(f"预配置失败: [ {cmd} ]")
			exit(3)
		if os.system(f"make") != 0:
			print("预编译失败: [ make ]")
			exit(4)

	def install(self):
		"""
		安装
		:return:
		"""
		print("正在安装")
		os.chdir(self.tmp_dir)
		if os.system(f"make install") != 0:
			print("安装失败")
			exit(5)

	def clean(self):
		"""
		清理
		:return:
		"""
		print("正在清理")
		if os.path.exists(self.tmp_dir):
			os.system(f"rm -rf {self.tmp_dir}")
			os.system(f"rm -rf {self.filename}")
		if os.path.exists(self.filename):
			os.system(f"rm -f {self.filename}")

	def backup(self):
		"""
		备份
		:return:
		"""
		print("正在备份")
		# 获取openssl路径并加上_bak进行备份
		s = subprocess.getstatusoutput("which openssl")
		if s[0] == 0:
			# 拼接新的备份
			os.system(f"cp -f {s[1]} {s[1]}_bak")
			# 删除旧的备份
			os.remove(s[1])
			self.openssl_old_path = s[1]

	def env(self):
		"""
		将/usr/local/lib永久设置到系统环境变量LD_LIBRARY_PATH
		:return:
		"""
		print("正在设置环境变量")
		conf = f"/etc/ld.so.conf.d/openssl{str(v).replace('.', '')}.conf"
		try:
			with open(conf, "w", encoding="utf-8") as f:
				f.write(f"{self.lib} \n")
			print(f"写入成功: [ {conf} ]")
		except Exception as e:
			print(f"写入失败: [ {conf} ]")
			print(e)
			exit(9)

		c = "ldconfig"
		if os.system(c) != 0:
			print(f"库信息配置失败: [ {c} ]")
			exit(12)
		else:
			print(f"库信息配置成功: [ {c} ]")

	def link(self):
		"""
		将openssl可执行文件链接到现有的PATH路径
		:return:
		"""
		# 获取当前openssl绝对路径
		if self.openssl_old_path is not None:
			c = f"ln -s {self.openssl_path} {self.openssl_old_path}"
			if os.system(c) != 0:
				print(f"链接失败: [ {c} ]")
				exit(10)
			else:
				print(f"链接成功: [ {c} ]")
		else:
			c = f"ln -s {self.openssl_path} /usr/binary/openssl"
			if os.system(c) != 0:
				print(f"链接失败: [ {c} ]")
				exit(11)
			else:
				print(f"链接成功: [ {c} ]")

	def start(self):
		self.download()
		self.untar()
		self.compile()
		self.install()
		self.backup()
		self.link()
		self.env()
		self.clean()
		print("OpenSSL升级成功,请自行重启或升级SSH")


def use():
	"""
	使用免责声明
	:return:
	"""
	print("""
	免责声明:
	操作系统环境问题由使用者自行维护,此脚本只是个人编写，不代表任何平台或单位
	1. 本脚本仅供学习交流使用,请勿用于非法用途
	2. 脚本作者不对因使用本脚本而导致的任何问题或损失负责,请先自行阅读源码后再决定是否继续
	3. 可接受脚本bug反馈，但是不提供使用指导,请自行判断,不懂的地方可以通过-h参数获取帮助
	4. 如遇到代码问题可自行修改源码或者反馈，但是作者不会保障及时的修复
	OpenSSL属于底层库，很多程序都依赖它，所以安装之前请先评估风险，否则请勿安装
	OpenSSL属于底层库，很多程序都依赖它，所以安装之前请先评估风险，否则请勿安装
	OpenSSL属于底层库，很多程序都依赖它，所以安装之前请先评估风险，否则请勿安装
	""")
	while True:
		c = input("是否继续?(y/n): ")
		if c.lower().strip() == "y".lower():
			break
		elif c.lower().strip() == "n".lower():
			exit(0)
		else:
			print("输入错误,请重新输入")


if __name__ == "__main__":
	# 设置传参自定义URL
	url = "https://github.com/openssl/openssl/releases/download/openssl-3.5.0/openssl-3.5.0.tar.gz"
	v = str(url).split("/")[-1].replace(".tar.gz", "")
	arg = ArgumentParser(description='当前脚本版本: 1.0_20250528', prog="OpenSSL-Compile-Install")
	arg.add_argument("-u", "--url", help=f"定义升级地址,默认: {url}", default=url)
	arg.add_argument("-f", "--file", help=f"手动指定压缩包路径,不从网页下载(默认使用网页下载)", required=False)
	default_dst = f"/usr/local/{v}"
	arg.add_argument("-d", "--dst", help=f"设置程序安装目录,默认: {default_dst}", default=default_dst, required=False)
	url = arg.parse_args().url
	file_arg = arg.parse_args().file
	use()
	upgrade = UpgradeOpenSSL(urls=url, dst=arg.parse_args().dst, file=file_arg)
	upgrade.start()
